package parser;
import java.util.ArrayList;
import scanner.*;
import parser.nodes.*;
public class ParseTreeGenerator {
	
	int index;
	ArrayList<Token> tokens;
	String currToken;
	public ParseTreeGenerator(ArrayList<Token> tokens)
	{
		index = 0;
		this.tokens = tokens;
	}
	
	public String getNextToken()
	{
		index++;
		return ((Token)tokens.get(index)).getValue();
	}
	public String getToken()
	{
		return ((Token)tokens.get(index)).getValue();
	}
	
	public AstNode generateParseTree()
	{
		try{
		matchToken("begin");
		String token = currToken;
		AstNode retval = null;
		if(!token.equals("begin"))
		{
			
			System.out.println("error");
		}
		else
			System.out.println(token);
		retval = statement_list();
		matchToken("end");
		token = currToken;
		if(token.equals("end"))
		{
			//token = getNextToken();
			System.out.println("end");
		}
		return retval;
		}catch(NullPointerException e){System.out.println("Improper Syntax of Script");e.printStackTrace();return null;}
	}
	private void matchToken()
	{
		String token = "";
		String temp = "";
		//temp = ((Token)tokens.get(index)).getValue();
		//index++;
	//	if(!temp.equals("\"")&&!temp.equals("\"")){
		while(true)
		{
			
			
			temp = getToken();
			
			
				token += temp;
				index++;
				
				if(temp.equals("\"")||temp.equals("'")||temp.equals("=")||temp.equals(";")||temp.equals("(")||temp.equals(")"))
					break;
			
		}
		//}
		token = token.substring(0, token.length()-1);
		index--;
		//System.out.println(token);
		currToken = token;
		return;
	}
	private void matchPrintToken()
	{
		String token = "";
		String temp = "";
		//temp = ((Token)tokens.get(index)).getValue();
		//index++;
	//	if(!temp.equals("\"")&&!temp.equals("\"")){
		while(true)
		{
			
			
			temp = getToken();
			
			
				token += temp;
				index++;
				
				if(temp.equals("\"")||temp.equals(",")||temp.equals("'")||temp.equals("=")||temp.equals(";")||temp.equals("(")||temp.equals(")"))
					break;
			
		}
		//}
		token = token.substring(0, token.length()-1);
		index--;
		//System.out.println(token);
		currToken = token;
		return;
	}
	private void matchRegexToken()
	{
		String token = "";
		String temp = "";
		//temp = ((Token)tokens.get(index)).getValue();
		//index++;
	//	if(!temp.equals("\"")&&!temp.equals("\"")){
		while(true)
		{
			
			
			temp = getToken();
			
			
				token += temp;
				index++;
				
				if(temp.equals("\"")||temp.equals("'"))
					break;
			
		}
		//}
		token = token.substring(0, token.length()-1);
		index--;
		//System.out.println(token);
		currToken = token;
		return;
	}
	private String matchToken(char c) {
		// TODO Auto-generated method stub
		return null;
	}
	private void matchToken(String string) {
		String token = "";
		String temp = "";
		
		for(int i = 0;i<string.length();i++)
		{
			temp = ((Token)tokens.get(index)).getValue();
			index++;
			if(temp.equals(Character.toString(string.charAt(i))))
			{
				token += temp;
			}
			else
				System.out.println("Error matching token:"+temp);
			
		}
		
		currToken = token;
		return;
	}

	private AstNode statement_list() {
		// TODO Auto-generated method stub
		StatementListNode list = new StatementListNode();
		list.setLchild(statement());
		list.setRchild(statement_list_tail());
		return list;
	}

	private AstNode statement_list_tail() {
		// TODO Auto-generated method stub
		String token = getToken();
		if(token.equals("e")) //end
		{return null;}
		
		StatementListNode list = new StatementListNode();
		list.setLchild(statement());
		token = getToken();
		if(token.equals("e")) //end
		{return list;}
		list.setRchild(statement_list_tail());
		return list;
	}

	private AstNode expression() {
		// TODO Auto-generated method stub
		String token = currToken;// tokens.get(index);
		/*if(token.equals("OPENPAR"))
		{
			System.out.println(token);
			token = getNextToken();
			expression();
			System.out.println(token);
			token = getNextToken();
			exp_tail();
		}
		else */
		if(token.equals("find"))
		{
			
			System.out.println(token);
			return exp_tail();
		}
		else
		{
			matchToken();
			token = currToken;
			System.out.println(token);//ID
			//TODO lookupToken(ID);
			LiteralNode literal = new LiteralNode();
			literal.setIdentifier(token);
			getToken();
			return literal; //TODO return lookupToken(ID);
		}
	}

	private AstNode printExpression() {
		// TODO Auto-generated method stub
		String token = getToken();// tokens.get(index);
		/*if(token.equals("OPENPAR"))
		{
			System.out.println(token);
			token = getNextToken();
			expression();
			System.out.println(token);
			token = getNextToken();
			exp_tail();
		}
		else */
		if(token.equals("\""))
		{
			matchToken("\"");
			matchToken();
			LiteralNode literal = new LiteralNode();
			literal.setIdentifier(currToken);
			matchToken("\"");
			return literal; 
		}
		else if(currToken.equals("find"))
		{
			
			System.out.println(currToken);
			return exp_tail();
		}
		else
		{
			matchPrintToken();
			token = currToken;
			System.out.println(currToken);//ID
			
			LiteralNode literal = new LiteralNode();
			literal.setIdentifier(currToken);
			
			return literal; 
		}
	}
	

	private FindNode term() {
		// find REGEX in  <file-name>  
		FindNode temp = new FindNode();
		String token = getToken();
		matchToken("'");
		System.out.println(currToken);
		matchRegexToken();
		token = currToken;
		System.out.println(token); //REGEX
		temp.setREGEX(token);
		matchToken("'");
		System.out.println(currToken); //'
		matchToken("in");
		System.out.println(currToken); //in
		matchToken("\"");
		System.out.println(currToken); //"
		matchToken();
		token = currToken;
		System.out.println(token); //filename
		temp.setFilename("./"+currToken);
		matchToken("\"");
		System.out.println(currToken); //"
		return temp;
	}



	private AstNode exp_tail() {
		// <bin-op><term><exp-tail> 
		String token = currToken;
		FindNode left = null;
		AstNode right = null;
		if(token.equals("find"))
		{
			System.out.println(token);
			left=term();
			
			token = getToken();
			if(token.equals(";"))
			{
				
				return left; 
			}
		}
		
		token = getToken();
		if(token.equals("d"))
		{
			matchToken("diff");
			
			DiffNode temp = new DiffNode();
			temp.lchild = left;
			System.out.println(currToken); //diff
			
			matchToken();
			temp.rchild=exp_tail();
			return temp;
		}
		else if(token.equals("u"))
		{
			matchToken("union");
			UnionNode temp = new UnionNode();
			temp.lchild = left;
			System.out.println(currToken); //diff
			
			matchToken();
			temp.rchild=exp_tail();
			
			return temp;
		}
		else if(token.equals("i"))
		{
			matchToken("inters");
			IntersectNode temp = new IntersectNode();
			temp.lchild = left;
			System.out.println(currToken); //diff
			
			matchToken();
			temp.rchild=exp_tail();
			
			return temp;
		}
		else
			return null;
	}



	private AstNode statement() {
		// TODO Auto-generated method stub
		matchToken();
		String token = currToken;
		
		
		if(token.equals("print"))
		{
			PrintNode temp = new PrintNode();
			System.out.println(token); // print
			matchToken("(");
			System.out.println(currToken);
			//matchToken();
			//System.out.println(currToken);
			temp.setLchild(expression_list());
			//matchToken(")");
			System.out.println(currToken);
			matchToken(";"); // ;
			System.out.println(currToken);
			return temp;
			
		}
		else if(token.equals("replace"))
		{
			ReplaceNode temp = new ReplaceNode();
			System.out.println(token); // replace
			matchToken("'");
			System.out.println(currToken); //'
			matchRegexToken();
			token = currToken;
			System.out.println(token); //REGEX
			temp.setRegex(token);
			matchToken("'");
			System.out.println(currToken); //'
			matchToken("with");
			System.out.println(currToken); // with
			matchToken("\"");
			System.out.println(currToken); // "
			matchToken();
			temp.setReplacement(currToken);
			System.out.println(currToken); // replacement
			matchToken("\"");
			System.out.println(currToken); // "
			matchToken("in");
			System.out.println(currToken); // in
			
			matchToken("\"");
			System.out.println(currToken); //"
			matchToken();
			System.out.println(currToken); // sourcefile
			temp.setInputFileName("./"+currToken);
			matchToken("\"");
			System.out.println(currToken); //"
			matchToken(">!");
			System.out.println(currToken); // >!
			matchToken("\"");
			System.out.println(currToken); //"
			matchToken();
			System.out.println(currToken); // destination
			temp.setOutputFileName("./"+currToken);
			matchToken("\"");
			System.out.println(currToken);//"
			matchToken(";");
			
			System.out.println(currToken); // ;
			
			return temp;
		}
		else if(token.equals("recursivereplace"))
		{
			RecursiveReplaceNode temp = new RecursiveReplaceNode();
			System.out.println(getToken()); // recursivereplace
			matchToken("'");
			System.out.println(currToken); //'
			matchRegexToken();
			token = currToken;
			System.out.println(token); //REGEX
			temp.setRegex(token);
			matchToken("'");
			System.out.println(currToken); //'
			matchToken("with");
			System.out.println(currToken); // with
			matchToken("\"");
			System.out.println(currToken); // "
			matchToken();
			temp.setReplacement(currToken);
			System.out.println(currToken); // replacement
			matchToken("\"");
			System.out.println(currToken); // "
			matchToken("in");
			System.out.println(currToken); // in
			
			matchToken("\"");
			System.out.println(currToken); //"
			matchToken();
			System.out.println(currToken); // sourcefile
			temp.setInputFileName("./"+currToken);
			matchToken("\"");
			System.out.println(currToken); //"
			matchToken(">!");
			System.out.println(currToken); // >!
			matchToken("\"");
			System.out.println(currToken); //"
			matchToken();
			System.out.println(currToken); // destination
			temp.setOutputFileName("./"+currToken);
			matchToken("\"");
			System.out.println(currToken);//"
			matchToken(";");
			
			System.out.println(currToken); // ;
			return temp;
		}
		AssignmentNode assignment = new AssignmentNode();
		LiteralNode literal = new LiteralNode();
		literal.setIdentifier(currToken);
		System.out.println(currToken); 
		assignment.setLchild(literal);
		
		
		matchToken("=");
		System.out.println(currToken); 
		token = getToken();
		if(token.equals("#"))
		{
			HashNode temp = new HashNode();
			matchToken("#");
			System.out.println(currToken); //#
			temp.lchild = expression();
			
			assignment.setRchild(temp);
			matchToken(";");
			
			System.out.println(currToken); // ;
			return assignment;
		}
		else 
			matchToken();
		token = currToken;
		if(token.equals("maxfreqstring"))
		{
			MaxFreqStringNode temp = new MaxFreqStringNode();
			LiteralNode literal2 = new LiteralNode();
			System.out.println(token); //maxfreqstring
			matchToken("(");
			System.out.println(currToken); // openpar
			
			
			
			matchToken();
			System.out.println(currToken);//id
			//TODO lookup for identifier
			//assignment.setValue(lookupValue(ID));
			literal2.setIdentifier(currToken);
			temp.setLchild(literal2);
			
			//literal2.setParent(temp);
			assignment.setRchild(temp);
			//temp.setParent(assignment);
			matchToken(")");
			System.out.println(currToken); // closepar
			matchToken(";");
			System.out.println(currToken); // ;
			return assignment;
		}
		else
		{
			assignment.setRchild(expression());
			matchToken(";");
			System.out.println(currToken); // ;
			return assignment;
		}
	}

	private AstNode expression_list() {
		ExpressionListNode list = new ExpressionListNode();
		list.lchild = printExpression();
		list.rchild = expression_list_tail();
		return list;
	}

	private AstNode expression_list_tail() {
		String token = getToken();
		if(token.equals(")"))
		{matchToken(")");	return null;}
		matchToken(",");
		System.out.println(currToken); //,
		
		ExpressionListNode list = new ExpressionListNode();
		list.lchild = printExpression();
		list.rchild = expression_list_tail();
		return list;

	}
	
	public static void main(String[] args)
	{
		/*ArrayList<Token> tokens = new ArrayList<Token>();
		tokens.add(new Token("begin",""));
		tokens.add(new Token("matches",""));
		tokens.add(new Token("EQUALS",""));
		tokens.add(new Token("find",""));
		tokens.add(new Token("'[A-Z a-z]*ment[A-Z a-z]*'",""));
		tokens.add(new Token("in",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("file1.txt",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("intersec",""));
		tokens.add(new Token("find",""));
		tokens.add(new Token("'(A|a) [A-Z a-z]*'",""));
		tokens.add(new Token("in",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("file2.txt",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("SEMICOLON",""));
		tokens.add(new Token("num_matches",""));
		tokens.add(new Token("EQUALS",""));
		tokens.add(new Token("#",""));
		tokens.add(new Token("matches",""));
		tokens.add(new Token("SEMICOLON",""));
		
		tokens.add(new Token("print",""));
		tokens.add(new Token("OPENPAR",""));
		tokens.add(new Token("num_matches",""));
		tokens.add(new Token("CLOSEPAR",""));
		tokens.add(new Token("SEMICOLON",""));
		
		tokens.add(new Token("replace",""));
		tokens.add(new Token("'[A-Z a-z]*ment'",""));
		tokens.add(new Token("with",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("in",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("file1.txt",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token(">!",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("file3.txt",""));
		tokens.add(new Token("\"",""));
		tokens.add(new Token("SEMICOLON",""));
		
		tokens.add(new Token("end",""));
		ParseTreeGenerator test = new ParseTreeGenerator(tokens);
		test.generateParseTree();*/
		
	}
}
